﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using BeatEmUp.Enums;
using System.Diagnostics;

namespace BeatEmUp.Items.Weapons
{
    [Serializable]
    class Weapon:Item
    {
        //Stats to return and serialize
        public WeaponStatsForSerialization serialisationInfo;

        //Statistics values
        public int damageMin;
        public int damageMax;
        public int criticalHitChance;
        public int accuracy;
        //Statistics weights
        float totalDamageWeight = 2f;
        float criticalChanceWeight = 5.0f;
        float accuracyWeight = 2.0f;

        float weaponValue;

        int compareToPlayer = 0;
        string textureName;

        Random rand;
        public Weapon(int monsterLevel,MonsterType monsterType,string name,string textureName, Texture2D texture, int level,Vector2 position,WeaponLocation location) :
            base(name, texture,level,position,location)
        {
            rand = new Random();
            CalculateWeaponStatistics(monsterLevel, monsterType);
            this.weaponValue = 0;
            this.textureName = textureName;

            CalculateWeaponValue();
            Debug.WriteLine("New weapon with name " + name + " \r\nMin damage: " + damageMin + " \r\nMax damage: " + damageMax +
                " \r\nCritical hit chance: " + criticalHitChance + " \r\nAccuracy: " + accuracy + " \r\nValue: " + weaponValue +
                " was generated.");
            serialisationInfo = new WeaponStatsForSerialization();

            serialisationInfo.damageMin = this.damageMin;
            serialisationInfo.damageMax = this.damageMax;
            serialisationInfo.criticalHitChance = this.criticalHitChance;
            serialisationInfo.accuracy = this.accuracy;
            serialisationInfo.totalDamageWeight = this.totalDamageWeight;
            serialisationInfo.criticalChanceWeight = this.criticalChanceWeight;
            serialisationInfo.accuracyWeight = this.accuracyWeight;
            serialisationInfo.weaponValue = this.weaponValue;
            serialisationInfo.compareToPlayer = this.compareToPlayer;
            serialisationInfo.Height = this.Height;
            serialisationInfo.Width = this.Width;
            serialisationInfo.TextureName = this.TextureName;
            serialisationInfo.Position = this.position;
            serialisationInfo.name = this.name;
            serialisationInfo.level=this.level;
        }

        private void CalculateWeaponStatistics(int monsterLevel, MonsterType monsterType)
        {
            if (monsterType == MonsterType.Boss)
                monsterLevel += 5;
            damageMin = 10+monsterLevel + rand.Next(Convert.ToInt32(Math.Pow(monsterLevel, 1.7)));
            int damageDifference = rand.Next(damageMin);
            damageMax = damageMin + damageDifference;
            criticalHitChance = rand.Next(monsterLevel);
            double randomAccuracy = rand.Next((int)Math.Pow(monsterLevel, 1.05));
            if (randomAccuracy > 35) randomAccuracy = 35;
            accuracy = 100-rand.Next(0,(int)randomAccuracy);
        }

        private void CalculateWeaponValue()
        {
            weaponValue += damageMin+(damageMax - damageMin) * totalDamageWeight;
            weaponValue += criticalHitChance * criticalChanceWeight;
            weaponValue -= accuracyWeight * (100 - accuracy);
            base.CalculateValue(weaponValue);
        }

        public int CalculateDamage()
        {
            int damage = rand.Next(damageMax - damageMin) + damageMin;
            if (criticalHitChance > 0)
            {
                int result = rand.Next(100)+1;
                if (result <= criticalHitChance)
                {
                    damage *= 2;
                    Debug.WriteLine("Critical damage done.");
                }
            }
            if (accuracy < 100)
            {
                int result = rand.Next(100) + 1;
                if(result<=100-accuracy)
                    damage = 0;
            }
            Debug.WriteLine("Done " + damage + " damage to enemy.");
            return damage;
        }

        public void Draw(SpriteBatch sb)//Wyrysowanie broni
        {
           
            if (compareToPlayer == 2) GameManager.customResolution.Draw(texture, Bounds, Color.Green);
            if (compareToPlayer == 1) GameManager.customResolution.Draw(texture, Bounds, Color.White);
            if (compareToPlayer == 0) GameManager.customResolution.Draw(texture, Bounds, Color.Red);
            //serialisationInfo.TextureName = this.TextureName;
        }

        public int Height
        {
            get
            {
                return texture.Height;
            }
            set 
            { 
            }
        }

        public int Width
        {
            get
            {
                return texture.Width;
            }
            set 
            {
            }
        }

        public Texture2D Texture
        {
            get
            {
                return texture;
            }
        }

        public int CompareToPlayer
        {
            get
            {
                return compareToPlayer;
            }
            set
            {
                compareToPlayer = value;
            }
        }

        public string TextureName
        {
            get
            {
                return textureName;
            }
            set
            {
                textureName = value;
            }
        }

        public Rectangle Position
        {
            get
            {
                return new Rectangle((int)position.X, (int)position.Y, Width, Height);
            }
        }

        public string GetWeaponDescription()
        {
            return "Name: " + name + " \r\nMin damage: " + damageMin + " \r\nMax damage: " + damageMax +
                " \r\nCritical hit chance: " + criticalHitChance + " \r\nAccuracy: " + accuracy;
        }

        public string GetDescriptionWithComparision(Weapon weapon)
        {
            string text = "";
            text+= "Name: " + name;
            text += "\r\nMin damage: " + damageMin + " (" + GetDifference(weapon.damageMin,damageMin) + ")";
            text += "\r\nMax damage: " + damageMax + " (" + GetDifference(weapon.damageMax, damageMax) + ")";
            text += "\r\nCritical hit chance: " + criticalHitChance + " (" + GetDifference(weapon.criticalHitChance, criticalHitChance) + ")";
            text += "\r\nAccuracy: " + accuracy + " (" + GetDifference(weapon.accuracy, accuracy) + ")";
            return text;
        }

        private string GetDifference(int value1,int value2)
        {
            int difference = value2-value1;
            string addition = "";
            if (difference > 0)
                addition = "+";
            return addition + difference.ToString();
        }

        public void Move(int by, Direction direction)
        {
            this.position.X += (int)direction * by;
        }

        internal WeaponStatsForSerialization GetWeaponFullInfo()
        {
            return this.serialisationInfo;
        }

        internal void setTextureName(string name)
        {
            this.texture.Name = name;
        }

        internal void SetWeaponFullInfo(GameManager gm, WeaponStatsForSerialization serialisationInfo)
        {
            Dictionary<string, Texture2D> weaponSprites;
            weaponSprites = new Dictionary<string, Texture2D>();
            weaponSprites = HelpMethods.LoadContentFromFolder<Texture2D>( gm.Content, @"Sprites\Weapons");

            //Texture2D weaponTexture = weaponSprites[textureName];

            this.damageMin = serialisationInfo.damageMin;
            this.damageMax = serialisationInfo.damageMax;
            this.criticalHitChance = serialisationInfo.criticalHitChance;
            this.accuracy = serialisationInfo.accuracy;
            this.totalDamageWeight = serialisationInfo.totalDamageWeight;
            this.criticalChanceWeight = serialisationInfo.criticalChanceWeight;
            this.accuracyWeight = serialisationInfo.accuracyWeight;
            this.weaponValue = serialisationInfo.weaponValue;
            this.compareToPlayer = serialisationInfo.compareToPlayer;
            this.Height = serialisationInfo.Height;
            this.Width = serialisationInfo.Width;
            //this.texture.Name = serialisationInfo.TextureName;//It might be better to swich it to property than a field
            //this.Texture.Name = serialisationInfo.TextureName;
            //this.textureName = serialisationInfo.TextureName;
            this.setTextureName(serialisationInfo.TextureName);
            this.texture.Name = serialisationInfo.TextureName;
            this.TextureName = serialisationInfo.TextureName;
            this.texture = weaponSprites[textureName];
            this.position = serialisationInfo.Position;//It might be better to swich it to property than a field
            this.name = serialisationInfo.name;
            this.level = serialisationInfo.level;
        }

        internal void changeTextureToCurrent()
        {
            throw new NotImplementedException();
        }
    }
}
